package utils;

import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * 时间工具类
 *
 * @author sheen dong
 * @since 2020/11/24 9:58 下午
 **/
public class GlobalDateUtils {

    private static final DateTimeFormatter DEFAULT_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss");

    private static final ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");

    public static LocalDateTime getLocalDateTime() {
        return LocalDateTime.now(DEFAULT_ZONE);
    }

    public static LocalDate getLocalDate() {
        return LocalDate.now(DEFAULT_ZONE);
    }

    public static LocalTime getLocalTime() {
        return LocalTime.now(DEFAULT_ZONE);
    }

    public static LocalDateTime toLocalDateTime(String date) {
        return LocalDateTime.parse(date, DEFAULT_FORMAT);
    }

    public static LocalDate toLocalDate(String date) {
        return LocalDate.parse(date, DATE_FORMAT);
    }

    public static LocalTime toLocalTime(String date) {
        return LocalTime.parse(date, TIME_FORMAT);
    }

    public static LocalDateTime toLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(DEFAULT_ZONE).toLocalDateTime();
    }

    public static LocalDate toLocalDate(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(DEFAULT_ZONE).toLocalDate();
    }

    public static LocalTime toLocalTime(Date date) {
        Instant instant = date.toInstant();
        return instant.atZone(DEFAULT_ZONE).toLocalTime();
    }

    public static String getLocalDateTimeStr() {
        return toStr(getLocalDateTime());
    }

    public static String getLocalDateStr() {
        return toStr(getLocalDate());
    }

    public static String getLocalTimeStr() {
        return toStr(getLocalTime());
    }

    public static Date toDate(LocalDateTime localDateTime) {
        Instant instant = localDateTime.atZone(DEFAULT_ZONE).toInstant();
        return Date.from(instant);
    }

    public static String toStr(LocalDateTime localDateTime, String format) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(fmt);
    }

    public static String toStr(LocalDateTime localDateTime) {
        return toStr(localDateTime, "yyyy-MM-dd HH:mm:ss");
    }

    public static String toStr(LocalDate localDate) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return localDate.format(fmt);
    }

    public static String toStr(LocalTime localTime) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
        return localTime.format(fmt);
    }

    /**
     * 计算是不是同一天
     * @param one 日期1
     * @param two 日期2
     * @return true: 是同一天，false: 不是同一天
     */
    public static boolean isSameDay(LocalDateTime one, LocalDateTime two) {
        if (one == null || two == null) {
            return false;
        }else {
            return StringUtils.endsWithIgnoreCase(
                    toStr(one, "yyyy-MM-dd"),
                    toStr(two, "yyyy-MM-dd")
            );
        }
    }

    /**
     * 获取当前年份
     * @return yyyy
     */
    public static Integer getYear() {
        return getLocalDate().getYear();
    }

    /**
     * 获取当前月份
     * @return MM
     */
    public static Integer getMonth() {
        return getLocalDate().getMonthValue();
    }

    /**
     * 获取当前天数(相对于周)
     * @return dd
     */
    public static Integer getWeekDay() {
        return getLocalDateTime().getDayOfWeek().getValue();
    }

    /**
     * 获取当前天数(相对于月)
     * @return dd
     */
    public static Integer getDayOfMonth() {
        return getLocalDate().getDayOfMonth();
    }

    /**
     * 获取当前天数(相对于年)
     * @return dd
     */
    public static Integer getDayOfYear() {
        return getLocalDate().getDayOfYear();
    }

    /**
     * 获取当前时间(小时)
     * @return HH
     */
    public static Integer getHourOfDay() {
        return getLocalTime().getHour();
    }

    /**
     * 在周上加day天数，返回天数(相对于周)
     * @param weekday 周几
     * @param day     天数
     * @return        周几
     */
    public static Integer plusWeekday(int weekday, int day) {
        weekday += day;
        while (weekday > 7) {
            weekday -= 7;
        }
        return weekday;
    }

    /**
     * 获取当前学期
     * @return 学期,格式:yyyy-n (n:1上半学期，2下半学期)
     * 如果当前是2020(3-8月)，则当前学期 2019-2
     * 如果当前是2020(8-2月)，则当前学期 2020-1
     */
    public static String getCurrentSemester() {
        int semester;
        int year = getYear();
        int month = getMonth();
        if (3 < month && month < 8) {
            semester = 2;
            year -= 1;
        }else {
            semester = 1;
        }
        return (year) + "-" + (semester);
    }

    /**
     * 获取工作时间段
     * @return
     * <li>1:今天上午班次</li>
     * <li>2:今天下午班次</li>
     * <li>3:明天上午班次</li>
     */
    public static Integer getWorkTime() {
        int hour = getHourOfDay();
        if (0 < hour && hour < 11) { // 今天第一班
            return 1;
        }else if(hour < 17) {        // 今天第二班
            return 2;
        }else {
            return 3;                // 明天第一班
        }
    }

    /**
     * 计算最近周几的日期
     * @param weekDay 周几
     * @return  DATE类型日期
     */
    public static Date getRecentDateByWeekDate(int weekDay) {
        Calendar c = Calendar.getInstance();
        int todayWeekday = getWeekDay();
        int targetWeekday = (weekDay + 1) > 7 ? 1 : (weekDay + 1);
        int targetWeekMonth = c.get(Calendar.WEEK_OF_MONTH) + 1;

        if (todayWeekday == 7) {
            targetWeekMonth -= 1;
        }

        if (weekDay >= todayWeekday && weekDay != 7) {
            c.set(Calendar.DAY_OF_WEEK, weekDay + 1);
        }else {
            c.set(Calendar.WEEK_OF_MONTH, targetWeekMonth);
            c.set(Calendar.DAY_OF_WEEK, targetWeekday);
        }
        return c.getTime();
    }

    /**
     * 计算两个时间相差的天数绝对值
     * @param localDate1 时间一
     * @param localDate2 时间二
     * @return  相差天数绝对值
     */
    public static int getTimeDiffAbsValue(LocalDate localDate1, LocalDate localDate2) {
        return (int) Math.abs(localDate1.until(localDate2, ChronoUnit.DAYS));
    }
}